
#include "SefonIotPlatform.h"
#include "SefonIotLog.h"
#include "SefonIotMqttClient.h"


//NOTE!!! you must define the following topic in IOT consle before running this sample.
#define TOPIC_DATA           "$test/data"
#define SUB_TOPIC_DATA       "$test/sub"

#define MSG_LEN_MAX         (1024)


void event_handle(void *pcontext, void *pclient, sfiot_mqtt_event_msg_pt msg)
{
    uint32_t packet_id = (uint32_t)msg->msg;
    sfiot_mqtt_topic_info_pt topic_info = (sfiot_mqtt_topic_info_pt)msg->msg;

    switch (msg->event_type)
    {
    case SFIOT_MQTT_EVENT_UNDEF:
        SFIOT_LOG_INFO("undefined event occur.");
        break;

    case SFIOT_MQTT_EVENT_DISCONNECT:
        SFIOT_LOG_INFO("MQTT disconnect.");
        break;

    case SFIOT_MQTT_EVENT_RECONNECT:
        SFIOT_LOG_INFO("MQTT reconnect.");
        break;

    case SFIOT_MQTT_EVENT_SUBCRIBE_SUCCESS:
        SFIOT_LOG_INFO("subscribe success, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_SUBCRIBE_TIMEOUT:
        SFIOT_LOG_INFO("subscribe wait ack timeout, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_SUBCRIBE_NACK:
        SFIOT_LOG_INFO("subscribe nack, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_UNSUBCRIBE_SUCCESS:
        SFIOT_LOG_INFO("unsubscribe success, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_UNSUBCRIBE_TIMEOUT:
        SFIOT_LOG_INFO("unsubscribe timeout, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_UNSUBCRIBE_NACK:
        SFIOT_LOG_INFO("unsubscribe nack, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_PUBLISH_SUCCESS:
        SFIOT_LOG_INFO("publish success, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_PUBLISH_TIMEOUT:
        SFIOT_LOG_INFO("publish timeout, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_PUBLISH_NACK:
        SFIOT_LOG_INFO("publish nack, packet-id=%u", packet_id);
        break;

    case SFIOT_MQTT_EVENT_PUBLISH_RECVEIVED:
        SFIOT_LOG_INFO("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
                topic_info->topic_len,
                topic_info->ptopic,
                topic_info->payload_len,
                topic_info->payload);
        break;

    default:
        SFIOT_LOG_INFO("Should NOT arrive here.");
        break;
    }
}


void aliot_mqtt_msg_arrived(void *pcontext, void *pclient, sfiot_mqtt_event_msg_pt msg)
{
    sfiot_mqtt_topic_info_pt ptopic_info = (sfiot_mqtt_topic_info_pt) msg->msg;

    //print topic name and topic message
    SFIOT_LOG_INFO("topic=%.*s, topic_msg=%.*s",
            ptopic_info->topic_len,
            ptopic_info->ptopic,
            ptopic_info->payload_len,
            ptopic_info->payload);
}

int mqtt_client(void)
{
    SefonIotLogSetLevel(1);

    int rc = 0, msg_len, cnt = 0;
    void *pclient;
    sfiot_mqtt_param_t mqtt_params;
    sfiot_mqtt_topic_info_t topic_msg;
    char msg_pub[128];
    char *msg_buf = NULL, *msg_readbuf = NULL;

    if (NULL == (msg_buf = (char *)SefonIotPlatformMalloc(MSG_LEN_MAX))) {
        SFIOT_LOG_DEBUG("not enough memory");
        rc = -1;
        goto do_exit;
    }

    if (NULL == (msg_readbuf = (char *)SefonIotPlatformMalloc(MSG_LEN_MAX))) {
        SFIOT_LOG_DEBUG("not enough memory");
        rc = -1;
        goto do_exit;
    }

    /* Initialize MQTT parameter */
    memset(&mqtt_params, 0x0, sizeof(mqtt_params));

    mqtt_params.port = 1883;
    mqtt_params.host = "193.168.0.88";
    mqtt_params.client_id = "clientid123";
    mqtt_params.user_name = "admin";
    mqtt_params.password = "admin";
    mqtt_params.pub_key = NULL;

    mqtt_params.request_timeout_ms = 2000;
    mqtt_params.clean_session = 0;
    mqtt_params.keepalive_interval_ms = 60000;
    mqtt_params.pread_buf = msg_readbuf;
    mqtt_params.read_buf_size = MSG_LEN_MAX;
    mqtt_params.pwrite_buf = msg_buf;
    mqtt_params.write_buf_size = MSG_LEN_MAX;

    mqtt_params.handle_event.h_fp = event_handle;
    mqtt_params.handle_event.pcontext = NULL;


    /* Construct a MQTT client with specify parameter */
    pclient = SFIotMqttConstruct(&mqtt_params);
    if (NULL == pclient) {
        SFIOT_LOG_DEBUG("MQTT construct failed");
        rc = -1;
        goto do_exit;
    }

    /* Subscribe the specific topic */
    rc = SFIotMqttSubscribe(pclient, SUB_TOPIC_DATA, SFIOT_MQTT_QOS1, aliot_mqtt_msg_arrived, NULL);
    if (rc < 0) {
        SFIotMqttDeconstruct(pclient);
        SFIOT_LOG_DEBUG("SFIotMqttSubscribe failed, rc = %d", rc);
        rc = -1;
        goto do_exit;
    }

    SefonIotPlatformMsleep(1000);

    /* Initialize topic information */
    memset(&topic_msg, 0x0, sizeof(sfiot_mqtt_topic_info_t));
    strcpy(msg_pub, "message: hello! start!");

    topic_msg.qos = SFIOT_MQTT_QOS1;
    topic_msg.retain = 0;
    topic_msg.dup = 0;
    topic_msg.payload = (void *)msg_pub;
    topic_msg.payload_len = strlen(msg_pub);

    do {
        /* Generate topic message */
        cnt++;
        msg_len = snprintf(msg_pub, sizeof(msg_pub), "{\"attr_name\":\"temperature\", \"attr_value\":\"%d\"}", cnt);
        if (msg_len < 0) {
            SFIOT_LOG_DEBUG("Error occur! Exit program");
            rc = -1;
            break;
        }

        topic_msg.payload = (void *)msg_pub;
        topic_msg.payload_len = msg_len;

        rc = SFIotMqttPublish(pclient, TOPIC_DATA, &topic_msg);
        if (rc < 0) {
            SFIOT_LOG_DEBUG("error occur when publish");
            rc = -1;
            break;
        }
        //SFIOT_LOG_DEBUG("packet-id=%u, publish topic msg=%s", (uint32_t)rc, msg_pub);

        /* handle the MQTT packet received from TCP or SSL connection */
        SFIotMqttYield(pclient, 200);

        //aliot_platform_msleep(1000);

    } while (cnt < 100);

    SFIotMqttUnsubscribe(pclient, TOPIC_DATA);

    SefonIotPlatformMsleep(200);

    SFIotMqttDeconstruct(pclient);


do_exit:
    if (NULL != msg_buf) {
        SefonIotPlatformFree(msg_buf);
    }

    if (NULL != msg_readbuf) {
        SefonIotPlatformFree(msg_readbuf);
    }

    return rc;
}



int main()
{
    mqtt_client();

    SFIOT_LOG_DEBUG("out of sample!");

    return 0;
}

